package com.yuda.afterexamscore.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.yuda.afterexamscore.domain.SpotCheckAnswer;
import com.yuda.afterexamscore.mapper.SpotCheckAnswerMapper;
import com.yuda.afterexamscore.service.SpotCheckAnswerService;
import com.yuda.afterexamscore.vo.DpQuesScoreVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Service
public class SpotCheckAnswerServiceImpl implements SpotCheckAnswerService {

    @Autowired
    private SpotCheckAnswerMapper spotCheckAnswerMapper;

    public static Queue<DpQuesScoreVo> dpSubjectScoreQueue = new ConcurrentLinkedQueue<DpQuesScoreVo>();

    public static Queue<Object[]> objectQueue = new ConcurrentLinkedQueue<>();

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Override
    public List<SpotCheckAnswer> querySpotCheckAnswerTotal(SpotCheckAnswer spotCheckAnswer) {
        List<SpotCheckAnswer> spotCheckAnswers = new ArrayList<>();
        if (spotCheckAnswer.getEugenicsNum() == null && spotCheckAnswer.getUnfortunatelyNum()!=null){
            List<SpotCheckAnswer> spotCheckAnswersUnfortunate = spotCheckAnswerMapper.querySpotCheckAnswerTotalUnfortunate(spotCheckAnswer);
            List<SpotCheckAnswer> spotCheckAnswerExchangesUnfortunate =spotCheckAnswerMapper.querySpotCheckAnswerTotalUnfortunateExchange(spotCheckAnswer);
            if (CollectionUtil.isNotEmpty(spotCheckAnswerExchangesUnfortunate)){
                spotCheckAnswersUnfortunate.addAll(spotCheckAnswerExchangesUnfortunate);
            }
            spotCheckAnswers.addAll(spotCheckAnswersUnfortunate);
        }else {
            spotCheckAnswers = spotCheckAnswerMapper.querySpotCheckAnswerTotal(spotCheckAnswer);
            List<SpotCheckAnswer> spotCheckAnswerExchanges =spotCheckAnswerMapper.querySpotCheckAnswerTotalExchange(spotCheckAnswer);
            if (CollectionUtil.isNotEmpty(spotCheckAnswerExchanges)){
                spotCheckAnswers.addAll(spotCheckAnswerExchanges);
            }
            if (spotCheckAnswer.getUnfortunatelyNum()!=null){
                List<SpotCheckAnswer> spotCheckAnswersUnfortunate = spotCheckAnswerMapper.querySpotCheckAnswerTotalUnfortunate(spotCheckAnswer);
                List<SpotCheckAnswer> spotCheckAnswerExchangesUnfortunate =spotCheckAnswerMapper.querySpotCheckAnswerTotalUnfortunateExchange(spotCheckAnswer);
                if (CollectionUtil.isNotEmpty(spotCheckAnswerExchangesUnfortunate)){
                    spotCheckAnswersUnfortunate.addAll(spotCheckAnswerExchangesUnfortunate);
                }
                spotCheckAnswers.addAll(spotCheckAnswersUnfortunate);
            }
        }
        spotCheckAnswers = spotCheckAnswers.stream().collect(
                Collectors.collectingAndThen(Collectors.toCollection(
                        () -> new TreeSet<>(Comparator.comparing(o -> o.getStudentId()))), ArrayList::new)
        );
        spotCheckAnswers.sort(Comparator.comparing(SpotCheckAnswer::getRank));
        return spotCheckAnswers;
    }

    @Override
    public List<SpotCheckAnswer> querySpotCheckAnswer(SpotCheckAnswer spotCheckAnswer) {
        List<SpotCheckAnswer> spotCheckAnswers = new ArrayList<>();
        if (spotCheckAnswer.getEugenicsNum() == null && spotCheckAnswer.getUnfortunatelyNum()!=null){
            List<SpotCheckAnswer> spotCheckAnswerUnfortunates = spotCheckAnswerMapper.querySpotCheckAnswerUnfortunate(spotCheckAnswer);
            spotCheckAnswers.addAll(spotCheckAnswerUnfortunates);
        }else {
            spotCheckAnswers = spotCheckAnswerMapper.querySpotCheckAnswer(spotCheckAnswer);
            if (spotCheckAnswer.getUnfortunatelyNum()!=null){
                List<SpotCheckAnswer> spotCheckAnswerUnfortunates = spotCheckAnswerMapper.querySpotCheckAnswerUnfortunate(spotCheckAnswer);
                spotCheckAnswers.addAll(spotCheckAnswerUnfortunates);
            }
        }
        spotCheckAnswers = spotCheckAnswers.stream().collect(
                Collectors.collectingAndThen(Collectors.toCollection(
                        () -> new TreeSet<>(Comparator.comparing(o -> o.getStudentId()))), ArrayList::new)
        );
        spotCheckAnswers.sort(Comparator.comparing(SpotCheckAnswer::getRank));
        return spotCheckAnswers;
    }

    @Override
    public void updateMqType() throws InterruptedException {
        //清空队列
        dpSubjectScoreQueue.clear();
        objectQueue.clear();
        //todo 只适用于610 在之后自己的考试中可能会替换
        List<DpQuesScoreVo> vos = jdbcTemplate.query("SELECT b.student_id,b.subject_id subject_relation_id,IF(b.c=c.c,TRUE,FALSE) mqStatus from\n" +
                "(\n" +
                "SELECT student_id,subject_id,count(1) c from \n" +
                "(\n" +
                "SELECT student_id,subject_id,ques_id from mq_answer GROUP BY student_id,subject_id,ques_id\n" +
                ") a GROUP BY student_id,subject_id\n" +
                ") b,\n" +
                "(SELECT subject_id,count(1) c from dp_ques_index_mapping GROUP BY subject_id) c\n" +
                "where b.subject_id=c.subject_id", new BeanPropertyRowMapper<>(DpQuesScoreVo.class));
        dpSubjectScoreQueue.addAll(vos);
        //瓜分线程,每个线程处理100条数据
        ExecutorService executor = Executors.newFixedThreadPool(1000);
        int threadNum = (int) Math.ceil(vos.size()/100) + 1;
        if (threadNum>=1){
            CountDownLatch latch = new CountDownLatch(threadNum);
            if(threadNum > 0) {
                for (int i = 0; i < threadNum; i++) { // 开threadNum个线程
                    Runnable task = new SpotCheckAnswerServiceImpl.MultithreadingOfUpdateMqStatus(latch);
                    // 执行
                    executor.execute(task);
                }
            }
            latch.await(); //
        }
        //最后把mq_status状态为null的改为0
        System.out.println("把mq_status状态为null的改为0");
        jdbcTemplate.batchUpdate("update sparta_exam_subject_student set mq_status = 0 where mq_status is null");
        //在一个sparta_exam_student里更新mq_status状态
        System.out.println("查询mq状态");
        List<SpotCheckAnswer> spotCheckAnswers = jdbcTemplate.query("SELECT student_id,GROUP_CONCAT(mq_status) mq_status from sparta_exam_subject_student where quekao != 1 and stu_start_time != 0 GROUP BY student_id", new BeanPropertyRowMapper<>(SpotCheckAnswer.class));
        List<Object[]> objects = new ArrayList<>();
        for (SpotCheckAnswer spotCheckAnswer : spotCheckAnswers) {
            if (spotCheckAnswer.getMqStatus().contains("0")){
                objects.add(new Object[]{0,spotCheckAnswer.getStudentId()});
            }else {
                objects.add(new Object[]{1,spotCheckAnswer.getStudentId()});
            }
        }
        objectQueue.addAll(objects);
        int threadNum2 = (int) Math.ceil(objects.size()/100) + 1;
        if (threadNum2>=1){
            CountDownLatch latch2 = new CountDownLatch(threadNum2);
            if(threadNum2 > 0) {
                for (int i = 0; i < threadNum2; i++) { // 开threadNum个线程
                    Runnable task = new SpotCheckAnswerServiceImpl.MultithreadingOfUpdateMqStatusTotal(latch2);
                    // 执行
                    executor.execute(task);
                }
            }
            latch2.await(); //
        }
        executor.shutdown();//关闭线程池
        System.out.println("MQ状态跟新完毕");
    }

//    @Override
//    public List<SpotCheckAnswer> querySpotCheckAnswerUnfortunate(SpotCheckAnswer spotCheckAnswer) {
//        return spotCheckAnswerMapper.querySpotCheckAnswerUnfortunate(spotCheckAnswer);
//    }

//    @Override
//    public List<SpotCheckAnswer> querySpotCheckAnswerTotalUnfortunate(SpotCheckAnswer spotCheckAnswer) {
//        List<SpotCheckAnswer> spotCheckAnswers = spotCheckAnswerMapper.querySpotCheckAnswerTotalUnfortunate(spotCheckAnswer);
//        List<SpotCheckAnswer> spotCheckAnswerExchanges =spotCheckAnswerMapper.querySpotCheckAnswerTotalUnfortunateExchange(spotCheckAnswer);
//        if (CollectionUtil.isNotEmpty(spotCheckAnswerExchanges)){
//            spotCheckAnswers.addAll(spotCheckAnswerExchanges);
//        }
//        return spotCheckAnswers;
//    }

    /**
     * 多线程之MQ状态跟新完毕类
     *
     */
    private class MultithreadingOfUpdateMqStatusTotal implements Runnable {
        private CountDownLatch threadsSignal;
        public MultithreadingOfUpdateMqStatusTotal(CountDownLatch threadsSignal) {
            this.threadsSignal = threadsSignal;
        }

        @Override
        public void run() {
            List<Object[]> objects = new CopyOnWriteArrayList<>();
            for (int i = 0; i < 100; i++) {
                if (objectQueue.isEmpty()){
                    break;
                }
                Object[] poll = objectQueue.poll();//消费-省
                objects.add(poll);
            }
            jdbcTemplate.batchUpdate("UPDATE sparta_exam_student set mq_status = ? where student_id = ?",objects);
            // 线程结束时计数器减1
            threadsSignal.countDown();//必须等核心处理逻辑处理完成后才可以减1
            System.out.println(Thread.currentThread().getName() + "结束. 还有"+ threadsSignal.getCount() + " 个线程 ");
        }
    }

    /**
     * 多线程之MQ状态跟新完毕类
     *
     */
    private class MultithreadingOfUpdateMqStatus implements Runnable {
        private CountDownLatch threadsSignal;
        public MultithreadingOfUpdateMqStatus(CountDownLatch threadsSignal) {
            this.threadsSignal = threadsSignal;
        }

        @Override
        public void run() {
            List<Object[]> objects = new CopyOnWriteArrayList<>();
            for (int i = 0; i < 100; i++) {
                if (dpSubjectScoreQueue.isEmpty()){
                    break;
                }
                DpQuesScoreVo vo = dpSubjectScoreQueue.poll();//消费-省
                objects.add(new Object[]{vo.getMqStatus(),vo.getStudentId(),vo.getSubjectRelationId()});
            }
            jdbcTemplate.batchUpdate("update sparta_exam_subject_student set mq_status = ? where student_id = ? and subject_id = ?",objects);
            // 线程结束时计数器减1
            threadsSignal.countDown();//必须等核心处理逻辑处理完成后才可以减1
            System.out.println(Thread.currentThread().getName() + "结束. 还有"+ threadsSignal.getCount() + " 个线程 ");
        }
    }
}
